import { IMessageHandle } from "../interface/IMessageHandle";
import { IMessage } from "../interface/iMessage";
import { Bundle } from "../net/bundle/bundle";
import { MessageHeader } from "../net/message/header";
import { Packet } from "../net/packet/packet";
import { WebSocketClient } from "../net/webSocketClient/webSocketClient";
import { UtilsArray } from "../utils/Utils.Array";

export class MessageManager{
    private handles: Map<number, IMessageHandle> = new Map<number, IMessageHandle>();
    private allMessage:Map<number, ()=>IMessage>;
    private _recvData:Uint8Array;
    private _messageBundle: Bundle;
    private _recvHeader: MessageHeader;
    constructor(){
        this.allMessage = new Map<number, ()=>IMessage>();
        this._recvData = new Uint8Array(0);
        this._messageBundle = new Bundle();
        this._recvHeader = new MessageHeader();
    }

    private createMessage(number:number):IMessage|null{
        if(this.allMessage.has(number)){
            return this.allMessage!.get(number)!();
        }else{
            console.log("MessageManager createMessage error, number:" + number);
            return null;
        }
    }

    public registerMessage(number: number , message:()=>IMessage){
        if(this.allMessage.has(number)){
            console.log('message has register number:' + number);
            return;
        }
        this.allMessage.set(number, message);
    }

    public createBundle(): Bundle{
        let bundle:Bundle = new Bundle();
        return bundle;
    }

    public createPacket(opcode:number): Packet{
        let packet: Packet = new Packet(this.createMessage(opcode)!);
        return packet;
    }

    public onMessage(data:Uint8Array){
        this._recvData = UtilsArray.concatUint8Arrays(this._recvData, data);
    }

    public registerHandle(opcode: number, handle: IMessageHandle) {
        this.handles.set(opcode, handle);
    }

    public getHandle(opcode: number): IMessageHandle | null  {
        if (!this.handles.has(opcode)) {
            console.log('no handle for opcode: ' + opcode);
            return null;
        }
        return this.handles.get(opcode)!;
    }

    public pushPacket(packet: Packet, webSocket:WebSocketClient | null) {
        this._messageBundle.addPacket(packet);
        if(webSocket){
            this.sendBundle(webSocket);
        }
    }

    public sendBundle(webSocket:WebSocketClient) {
        if(webSocket){
            let isClear:boolean = webSocket.sendBundle(this._messageBundle);
            if (isClear){
                this._messageBundle = new Bundle();
            }
        }
    }

    public sliceRecvData(length: number):Uint8Array | null {
        if(this._recvData.length < length) {
            return null;
        }
        const data = this._recvData.slice(0, length);
        this._recvData = this._recvData.slice(length);
        return data;
    }

    public processMessage(){
        while(this._recvData.length > 0){
            if(this._recvHeader.Opcode == 0){
                if(this._recvData.length >= MessageHeader.HEADER_LENGTH){
                    let headerData = this.sliceRecvData(MessageHeader.HEADER_LENGTH);
                    this._recvHeader = new MessageHeader();
                    this._recvHeader.decode(headerData!);
                }
            }
            if(this._recvHeader.Opcode > 0){
                if(this._recvData.length >= this._recvHeader.Length){
                    let msgData = this.sliceRecvData(this._recvHeader.Length);
                    let msg = this.createMessage(this._recvHeader.Opcode);
                    if(msg != null){
                        msg.Decode(msgData!);
                        let msgHandler = this.getHandle(msg.GetOpcode());
                        if(msgHandler != null){
                            // msgHandler(msg.messageEntity);
                            msgHandler.handleMessage(msg.messageEntity);
                        }
                    }
                    this._recvHeader.reset();
                }
            }
        }
    }
}

const messageManager:MessageManager = new MessageManager();
export default messageManager;